package com.firewolf.hibernate.main;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.jdbc.Work;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.firewolf.hibernate.dto.News;

/***
 * 由于这里默认就是事务的，所以在commit之前，是不会修改数据库的数据的
 * @Description:
 * @Author: 刘兴
 * @Date : 2016年10月21日
 * @package : com.firewolf.hibernate.main
 * @Java_Version : 1.7
 * @Version : 2016年10月21日下午1:36:25
 */
public class MainDriver {

	private SessionFactory factory = null;
	
	private Session session = null;
	
	private Transaction transaction;

	@Before
	public void init() {
		Configuration cfg = new Configuration().configure();

		ServiceRegistry registry = new ServiceRegistryBuilder().applySettings(cfg.getProperties())
				.buildServiceRegistry();
		factory = cfg.buildSessionFactory(registry);
	}

	@After
	public void destory() {
		factory.close();
	}

	
	private void openSession(){
		session = factory.openSession();
		transaction = session.beginTransaction();
	}
	
	private void closeSession(){
		transaction.commit();
		session.close();
	}
	
	/**********************************新增数据************************************/
	/***
		新增数据有两个方法：
		save和persist	
		区别：
		当对一个 OID 不为 Null 的对象执行 save() 方法时, 会把该对象以一个新的 oid 保存到数据库中;  
		但执行 persist() 方法时会抛出一个异常.
	 ***/
	/**
	 Session.save():
	 	功能：向数据库插入一条数据；
	 	①.对象OID为null的时候，直接插入，
	 	②.为对象设置了OID【不管是不是在数据库中有对象OID的记录】，比喻为1000的时候，一样能向数据库插入一条数据，
	 	    在使用代理的情况下，OID会仍然按照数据库生成的，而不会是1000，即使用setId方法设置的OID是无效的
	 */
	@Test
	public void save() {
		openSession();

		News news = new News("十堰新闻ccc", "武松", new Date());
		session.save(news);
		
		News news2 = new News("十堰新闻ddd", "武松", new Date());
		news2.setId(10000);
		session.save(news2);
		
		closeSession();
	}
	
	/**
	 Session.persist():
	 	功能：向数据库插入一条数据
	 	①.如果没有设置OID，和save一样，会插入数据
	 	②.为对象设置了OID，会抛出一个异常：
	 		org.hibernate.PersistentObjectException: detached entity passed to persist
	 */
	@Test
	public void persist(){
		openSession();

		//正常插入
//		News news = new News("十堰新闻", "武松", new Date());
//		session.persist(news);
		
		//设置了OID
		News news2 = new News("十堰新闻2", "武松", new Date());
		news2.setId(10000);
		session.persist(news2);
		
		closeSession();
	}
	
	
	/*********************************删除数据************************************/
	
	@Test
	public void delete(){
		openSession();
		
		News n = (News) session.get(News.class, 2);
		session.delete(n);
		
		closeSession();
	}
	
	/******************************修改数据*****************************/
	/***
	 Session.update():
	 	功能：修改数据
	 	①.默认情况下，不管数据是否发生变化，都会进行update，如果希望只有当对象被修改了属性之后才执行
	 	  update()方法的话，可以为class节点设置select-before-update="true"
	 ***/
	
	@Test
	public void update(){
		openSession();
		
		News n = (News) session.get(News.class, 1);
		
//		n.setTitle("北京新闻333");
		session.update(n);
		
		closeSession();
	}
	
	/***
	 Session.saveOrUpdate():
	 	功能：包含了save()和update()方法；
	 	是执行那个方法的判断条件如下：
	 	①.Java 对象的 OID 为 null
		②.映射文件中为 <id> 设置了 unsaved-value  属性, 并且 Java 对象的 OID 
		    取值与这个 unsaved-value 属性值匹配

	 ***/
	@Test
	public void saveOrUpdate(){
		openSession();
		News n = new News("十堰新闻2", "武松", new Date());
//		News n = (News) session.get(News.class, 1);
//		n.setTitle("北京新闻444");
		session.saveOrUpdate(n);
		
		closeSession();
	}
	
	
	
	/**********************查询数据(根据OID)****************************/
	/***
		有两个方法：
		get();
		load();
		区别：
		①.当数据库中不存在与 OID 对应的记录时, load() 方法抛出 ObjectNotFoundException 异常, 而 get() 方法返回 null
		②.两者采用不同的延迟检索策略：load 方法支持延迟加载策略。而 get 不支持。
	 ***/
	
	/**
	 Session.get()
	 	功能：根据OID获取一条数据，
	 	①.会立即发送SQL语句
	 	②.不存在对应OID的记录的时候，会返回一个null
	 */
	@Test
	public void get(){
		openSession();
		
		News n = (News) session.get(News.class, 1000);
		
		//有没有下面这一句，都会发送sql语句
		System.out.println(n);
		closeSession();
		
	}
	
	/**
	Session.load():
		功能：根据OID从数据库查询出一条记录
		①.查询的对象不被使用的话，就不会发送SQL语句，懒加载
		②.如果OID在数据库中不存在对应的记录，就会抛出一个异常：
		org.hibernate.ObjectNotFoundException: No row with the given identifier exists:
	 */
	@Test
	public void load(){
		openSession();
		
		News n = (News) session.load(News.class, 1000);
		//没有下面这句，不会生成SQL，有的话，发送SQL
		System.out.println(n);
		closeSession();
	}
	
	/**
	 Session.merge():
	 	功能：把对象进行merge操作，具体流程看笔记
	 **/
	@Test
	public void merge(){
		openSession();
		News n = new News("测试", "wusong", new Date());
		n.setId(3);
		News merge = (News) session.merge(n);
		System.out.println(merge);
		closeSession();
	}
	
	
	/*****************Hibernate使用存储过程*******************/
	/**
	 Hibernate使用存储过程
	 **/
	public void userStoreProduce(){
		
		openSession();
		
		Work work = new Work() {
			
			@Override
			public void execute(Connection connection) throws SQLException {
				String procedure = "{call testProcedure()}";
				CallableStatement cstms = connection.prepareCall(procedure);
				cstms.executeUpdate();
			}
		};
		
		session.doWork(work);
		
		closeSession();
		
	}
}
